#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string>
#include <vector>
#include <list>
using namespace std;

// template <typename T>
// void Swap(T& left, T& right)
//{
//	T tmp = left;
//	left = right;
//	right = tmp;
// }
// int main()
//{
//	int a = 1, b = 2;
//	double c = 3.0, d = 4.0;
//	char e = 'x', f = 'y';
//	Swap(a, b);
//	Swap(c, d);
//	Swap(e, f);
//	cout << a << b << endl;
//	cout << c << d << endl;
//	cout << e << f << endl;
//	return 0;
// }

// template <class T>
// T Add(const T& left, const T& right)
//{
//	return left + right;
// }
// int main()
//{
//	/*int a = 1, b = 0;
//	double c = 1.0, d = 2.0;
//	Add(a, b);
//	Add(c, d);*/
//
//	int a = 10;
//	double b = 20.13;
//	cout << Add<int>(a, b) << endl;
//	cout << Add<double>(a, b) << endl;
//	return 0;
// }

//  这里编译器推不出来，就需要显式实例化  —————文心一言
// template<class T>
// T* func(int n)
//{
//	return new T[n];
//}
// int main()
//{
//	//func<double>(10);
//	func(10);
//	return 0;
//}

// //普通函数
// int Add(int left, int right)
//{
//	return left + right;
//}
//// 函数模板
// template<class T>
// T Add(T left, T right)
//{
//	return left + right;
// }
// int main()
//{
//	// 匹配调用原则：
//	// 1、合适匹配的情况下，有现成的就吃现成
//	// 2、没有就将就吃
//	// 3、有更合适就吃更合适的，哪怕要自己现做
//	cout << Add(1, 2) << endl;
//	cout << Add<int>(1, 2) << endl;
//	cout << Add(1.1, 2.2) << endl;
//
//	return 0;
// }

// #include <iostream>
// using namespace std;
//
//// 普通swap函数，可以接受任何两个相同类型的参数
// void swap(int& a, int& b) {
//     int temp = a;
//     a = b;
//     b = temp;
// }
//
//// 模板swap函数，可以接受任何两个相同类型的参数，但不允许隐式类型转换
// template <typename T>
// void swapTemplate(T& a, T& b) {
//     T temp = a;
//     a = b;
//     b = temp;
// }
//
// int main() {
//     int a = 5, b = 10;
//     double x = 5.5, y = 10.5;
//
//     // 使用普通swap函数交换两个int变量的值
//     swap(a, b);
//     cout << "After swapping ints with regular swap: a = " << a << ", b = " << b << endl;
//
//     // 使用模板swap函数交换两个int变量的值
//     swapTemplate(a, b);
//     cout << "After swapping ints with template swap: a = " << a << ", b = " << b << endl;
//
//     // 尝试使用模板swap函数交换两个不同类型的变量（double和int），这将导致编译错误
//     // 因为模板函数不允许隐式类型转换
//     // swapTemplate(x, a); // 这行代码将导致编译错误
//
//     // 使用普通swap函数交换两个double变量的值（假设我们有一个重载的swap函数用于double类型）
//     // 如果没有为double类型重载swap函数，这将导致编译错误，因为无法进行隐式类型转换
//     // 为了本例，我们假设有这样一个重载版本存在
//     // swap(x, y);
//     // cout << "After swapping doubles with regular swap: x = " << x << ", y = " << y << endl;
//
//     return 0;
// }

//// 普通函数可以进行自动类型转换
// void swap(int& a, int& b) {
//     int temp = a;
//     a = b;
//     b = temp;
// }
//// 模板函数不支持自动类型转换
// template <typename T>
// void swapTemplate(T& a, T& b) {
//     T temp = a;
//     a = b;
//     b = temp;
// }
// int main() {
//     int x = 5;
//     double y = 3.14;
//     cout << "Before swapping: x = " << x << ", y = " << y << endl;
//     // 使用模板函数尝试交换 x 和 y 的值，会导致编译错误
//     swapTemplate(x, y);
//     cout << "After swapping: x = " << x << ", y = " << y << endl;
//     return 0;
// }

////声明
// template<typename T>//要有
// void Swap(T& left, T& right);
////定义
// template<typename T>//要有
// void Swap(T& left, T& right)
//{
//	T temp = left;
//	left = right;
//	right = temp;
// }

// template<class T>
// class Stack {
// public:
//	Stack(T capacity = 4)
//		: _top(0)
//		, _capacity(capacity) {
//		_arr = new T[capacity];
//	}
//	~Stack() {
//		delete[] _arr;
//		_arr = nullptr;
//		_capacity = _top = 0;
//	}
// private:
//	T* _arr;
//	int _top;
//	int _capacity;
// };
//
// int main(void)
//{
//	Stack st1;   // 存储int
//	Stack st2;   // 存储double
//	return 0;
// }

// template<class T>
// class Stack
//{
// public:
//	//构造函数 (函数名和类名相同，不是类型名)  不写Stack<>
//	Stack(int n = 4);//声明
//
//	~Stack()
//	{
//		cout << "~Stack" << endl;
//		delete[] _a;
//		_a = nullptr;
//		_top = _capacity = 0;
//	}
//	void Push(const T& x)
//	{
//		//...
//	}
//
// private:
//	T* _a;
//	int _top;
//	int _capacity;
// };
//
////声明和定义分离的话要这样写（也不能放到两个文件，只能放到一个文件里，至于为何模板进阶的时候会讲）
////定义
// template<class T> //←记得加模板参数列表
// Stack<T>::Stack(int n) // 要指定 属于这个类域
//{
//	cout << "Stack(int n=4)" << endl;
//	_a = new T[n];
//	_top = 0;
//	_capacity = n;
// }
//
// int main()
//{
//	// 类模板都是显示实例化
//	Stack<int> st1;
//	Stack<double> st2;
//	return 0;
// }

//--------------------------------------STL简介

//---------------------------------------string
//
//
//
//
// string();
// string(const string& str);
// string(const string& str, size_t pos, size_t len = npos);
// string(const char* s);
// string(const char* s, size_t n);
// string(size_t n, char c);
// template <class InputIterator>  string(InputIterator first, InputIterator last);

// int main()
//{
//	string s1;							//构造空字符串
//	string s2("hello world");			//复制hello world到s2
//	string s3("hello,world", 3);		//复制hello world的前3个字符
//	string s4(s2, 0, 4);				//从s2的0位置开始，复制4个
//	string s5(s2, 3);					//从s2的3位置开始，一直复制到末尾
//	string s6(s2);
//	string s7 = s2;						//两个都是拷贝构造,复制s2的值
//	string s8(s2, 0, 10000);			//第三个参数大于字符串长度，就是一直复制直到末尾
//	//注意区别s3和s5;
//	string s9(9, 'a');					//填充9个'a'
//
////拓展：
//	string s10 = s2;//拷贝赋值操作，将 s2 的内容复制到 s1 中。
//	string s11 = "hello";
//	//字符串字面值会隐式转换为 std::string 对象，然后再赋给 s1。这涉及到了转换构造函数和拷贝赋值操作
//	string s12 = "x";
//	//由于 std::string 类型重载了接受单个字符作为参数的赋值运算符 (operator=)，这行代码将一个只包含字符 'x' 的字符串赋给了 s1
//	cout << s12 << endl;
//}

// #include<string>
//
//
////默认成员函数 以及一些重载版本
// int main()
//{
//	string s1;
//	string s2("hello world");
//	string s3 = s2;//拷贝构造
//	string s4(s2);//等价与上面
//
//	cout << s2 << endl;//重载了流插入和流体取，所以可以直接打印
//
////string (const string& str, size_t pos, size_t len = npos);
//	string s5(s2, 1, 4); //	从字符串 s2 中的指定位置开始，复制指定长度的字符到新创建的字符串对象 s5 中
//	cout << s5 << endl;
//
//	string s6(s2, 1);//如果第三个参数不给，就 有多少取多少，直到结束
//	cout <<"s6:" << s6 << endl;
//
//	string s7(s2,0 ,1000);//如果len给大了，也是取到结尾结束
//	cout << s6 << endl;
//
////string (const char* s, size_t n);
//	string s8("hello world", 4);//拷贝前4个   注意：如果这里写s2 就匹配成string(const string & str, size_t pos, size_t len = npos);
//	cout << "s8:" << s8 << endl;
////string (size_t n, char c);  连续填充n个c字符
//	string s9(3, 'a');
//	cout << s9 << endl;
//
//	s1 = s2;
//	cout << s1 << endl;
//
//	s1 = "world1";
//	cout << s1 << endl;
//
//	s1 = 'x';
//	cout << s1 << endl;
//	return 0;
//}

// 测试string容量相关的接口
// size/clear/resize
// int main()
//{
//
//	string s("hello, bit!!!");
//	cout << s.size() << endl;
//	cout << s.length() << endl;
//	cout << s.capacity() << endl;
//	cout << s << endl;
//
//	// 将s中的字符串清空，注意清空时只是将size清0，不改变底层空间的大小
//	s.clear();
//	cout << s.size() << endl;
//	cout << s.capacity() << endl;
//
//	// 将s中有效字符个数增加到10个，多出位置用'a'进行填充
//	// “aaaaaaaaaa”
//	s.resize(10, 'a');
//	cout << s.size() << endl;
//	cout << s.capacity() << endl;
//
//	// 将s中有效字符个数增加到15个，多出位置用缺省值'\0'进行填充
//	// "aaaaaaaaaa\0\0\0\0\0"
//	// 注意此时s中有效字符个数已经增加到15个
//	s.resize(15);
//	cout << s.size() << endl;
//	cout << s.capacity() << endl;
//	cout << s << endl;
//
//	// 将s中有效字符个数缩小到5个
//	s.resize(5);
//	cout << s.size() << endl;
//	cout << s.capacity() << endl;
//	cout << s << endl;
//	return 0;
// }

// 遍历和访问
// 1.[]  2.迭代器 3.范围for
int main()
{
    string s1("hello world");
    // 获取长度，既可以用size也可以用length  (不包含\0)
    cout << s1.size() << endl;
    ;
    cout << s1.length() << endl;
    for (size_t i = 0; i < s1.size(); i++)
    {
        cout << s1[i] << ' ';

        cout << s1.operator[](i) << " ";
    }
    cout << endl;
    s1[0] = 'x';
    s1[0] = 'h';
    // 让string逆置一下
    size_t begin = 0, end = s1.size() - 1;
    while (begin <= end)
    {
        // char tmp = s1[begin];
        // s1[begin] = s1[end];
        // s1[end] = tmp;
        swap(s1[begin], s1[end]); // swap 可以直接用了 不用再手搓啦

        ++begin; // 不要忘了噢~
        --end;
    }
    cout << s1 << endl;

    // string 的第二种遍历方式————迭代器
    // 属于string的类域
    // iterator的用法像指针
    string::iterator it = s1.begin();
    while (it != s1.end())
    {
        *it += 1; // 可以修改
        cout << *it << " ";
        ++it;
    }
    cout << endl;

    // reverse函数,任何容器，传迭代器区间进去，都能
    reverse(s1.begin(), s1.end());
    cout << s1 << endl;

    // 容器 vector,list.先用 后期再了解细节
    vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    vector<int>::iterator vit = v.begin(); // 迭代器都是左闭右开！
    while (vit != v.end())
    {
        cout << *vit << " ";
        ++vit;
    }
    cout << endl;

    // 逆置
    reverse(v.begin(), v.end());
    vit = v.begin();
    while (vit != v.end())
    {
        cout << *vit << " ";
        ++vit;
    }
    cout << endl;

    list<double> lt;
    lt.push_back(1.2);
    lt.push_back(1.3);
    lt.push_back(1.4);
    lt.push_back(1.5);
    list<double>::iterator lit = lt.begin();
    while (lit != lt.end())
    {
        cout << *lit << " ";
        lit++;
    }
    cout << endl;

    // 换种

    return 0;
}

////string底层
// namespace bit//如果不用命名空间的话会起命名冲突（与上面那段代码的string）
//{
//	class string
//	{
//	private:
//		char* _str;
//		size_t size;
//		size_t capacity;
//	};
// }

// 两个版本
// char& operator[] (size_t pos);    ---可读可写
// const char& operator[] (size_t pos) const;-----只读
// int main()
//{
//	string s1("hello world");
//	const string s2("hello world");
//	//以下这俩会自己调用各自的，第二个不能编译通过，
//	s1[0] = 'x';
//	//s2[0] = 'x';
//	cout << s2[0] << endl;
//
//	//s1 是一个非常量的 string 对象，而 s2 是一个常量的 string 对象。在 C++ 中，常量对象（如 const string）只能调用其对应的常量成员函数，而不能调用非常量成员函数。
//	//operator[] 是 string 类的成员函数，用于访问字符串中的字符。根据函数的重载，当你使用[] 运算符访问字符串时，编译器会根据对象的常量性自动选择调用合适的重载版本。
//	//对于 s1[0] = 'x'; ，由于 s1 是一个非常量对象，编译器会选择调用非常量版本的 operator[]，因此它能够成功编译并将字符串的第一个字符修改为 'x'。
//	//但是对于 s2[0] = 'x'; ，由于 s2 是一个常量对象，编译器会选择调用常量版本的 operator[]，而常量版本的 operator[] 返回的是一个 const char& 类型的引用，
//	//表示对字符串中字符的只读访问，因此不能对其进行赋值操作。因此，尝试对常量字符串的字符进行赋值操作会导致编译错误。
//
//
//	//迭代器 s1可以访问，s2不行  因为begin和end也提供了两个版本
//	string::iterator it = s1.begin();
//	//string::const_iterator it = s1.begin();   这样子*it就不会被修改了
//	while (it != s1.end())
//	{
//		*it += 1;//可以修改
//		cout << *it << " ";
//		++it;
//	}
//	cout << endl;
//
//
////上面的迭代器，list，vector都支持范围for
//	for (auto e : s1)
//	{
//		cout << e << " ";
//	}
//	cout << endl;
//
//	return 0;
//}

// int main() {
//     using namespace std;
//
//     string s = "Hello, World!";
//
//     try {
//         // 访问并打印指定位置的字符
//         cout << "Character at index " << s.at(3) << endl;
//     }
//     catch (const out_of_range& e) {
//         cout << "Error: " << e.what() << endl;
//     }
//
//     return 0;
// }